package FlowGraph.Transformations;

import java.util.*;

import antlr.collections.AST;
import antlr.*;

import FlowGraph.*;
import FlowGraph.Nodes.*;
import JavaGrammar.*;
import SymbolTable.*;
import util.*;

//////////////////////////////////////////////////////////////////////////
//// ForcConditionMethodExtraction
/**

@author Ivan Jeukens
@version v 0.1 12/11/2002
*/
public class ForConditionMethodExtraction extends Transformation {

    public ForConditionMethodExtraction(FlowGraph fg) {
        super(fg);
    }

    ///////////////////////////////////////////////////////////////////
    ////                        public  methods                    ////

    /* Para essa transformacao:
       arg0 = AST do comeco do method call: #(METHOD_CALL ...)
       arg1 = AST do nome do methodo: primeryExpression
       arg2 = AST com a lista de parametros: elist
       arg3 = no do fg com a chamada
       arg4 = tabela para pular chamadas no inicio da arvore AST
    */
    public void transform(LinkedList arguments) {
        AST n1 = (AST) arguments.get(0);
        AST n2 = (AST) arguments.get(1);
        AST n3 = (AST) arguments.get(2);
        FlowGraphNode node = (FlowGraphNode) arguments.get(3);
        HashMap skipMCTable = (HashMap) arguments.get(4);

        _extractForCondition(n1, n2, n3, node, skipMCTable);
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private methods                    ////

    /* Esse metodo introduz duas vezes a chamada da funcao. Uma antes do loop,
    e outra no final do corpo do loop. */
    private void _extractForCondition(AST n1, AST n2, AST n3, FlowGraphNode node,
            HashMap skipMCTable) {

        // Tambem uso no caso do while begin
        if(node.getType() == FlowGraphNode.FOR_BEGIN) {
            // Retira o que estiver na inicializacao do for
            ForInitializationExtraction ex = new ForInitializationExtraction(_flowGraph);
            ex.transform(node);
        }

        // Nome da variavel de atribuicao
        String varName;
	varName = new String("_tmp" + _flowGraph.getUniqueCount());
        _flowGraph.incrementUniqueCount();

        _firstMethodCall(varName, node, skipMCTable, n1, n2, n3);
        _secondMethodCall(varName, node, skipMCTable, n2, n3);
    }

    private void _firstMethodCall(String varName, FlowGraphNode node,
            HashMap skipMCTable, AST n1, AST n2, AST n3) {
        // Cria a  variavel de atribuicao e uma ST local para o novo no
        LinkedAST top = _createLocalVarAST(varName, null);
	STLocalVariableEntry entry = new STLocalVariableEntry(varName,
             STEntry.LOCAL, top, 0);
	SymbolTable st = new SymbolTable();
	st.putElement(entry.getName(), entry);

        CommonToken tok = new CommonToken(JavaTokenTypes.ASSIGN, "=");
        LinkedAST ast = new LinkedAST(tok);

	top.addChild(ast);
	ast.setParent(top);

        tok = new CommonToken(JavaTokenTypes.EXPR, "EXPR");
        LinkedAST expr = new LinkedAST(tok);
        
        ast.addChild(expr);
	expr.setParent(ast);
        
	tok = new CommonToken(JavaTokenTypes.METHOD_CALL, "(");
        LinkedAST mcast = new LinkedAST(tok);

	expr.addChild(mcast);
	mcast.setParent(expr);
		    
	ast = Util.dupTree(n2);
	mcast.addChild(ast);
	ast.setParent(mcast);

	ast = Util.dupTree(n3);
	mcast.addChild(ast);
	ast.setParent(mcast);
        
        MethodCallNode mc = new MethodCallNode(top);
        mc.setVarDef(true);
	skipMCTable.put(mc, mcast);
        
        // Atualiza a arvore AST.
	n1.setText(varName);
	n1.setType(JavaTokenTypes.IDENT);
	n1.setFirstChild(null);

        _addNodeBefore(mc, st, node, true);
    }

    // Inclui a chamada no final do loop
    private void _secondMethodCall(String varName, FlowGraphNode node,
            HashMap skipMCTable, AST n2, AST n3) {
        CommonToken tok = new CommonToken(JavaTokenTypes.EXPR, "EXPR");
        LinkedAST ast2 = new LinkedAST(tok);

        tok = new CommonToken(JavaTokenTypes.ASSIGN, "=");
	LinkedAST ast3 = new LinkedAST(tok);

        ast2.addChild(ast3);
        ast3.setParent(ast2);

        tok = new CommonToken(JavaTokenTypes.IDENT, new String(varName));
	LinkedAST ast4 = new LinkedAST(tok);

        ast3.addChild(ast4);
        ast4.setParent(ast3);

        tok = new CommonToken(JavaTokenTypes.METHOD_CALL, "(");
        LinkedAST ast5 = new LinkedAST(tok);

	ast3.addChild(ast5);
	ast5.setParent(ast3);

	LinkedAST ast = Util.dupTree(n2);
	ast5.addChild(ast);
	ast.setParent(ast5);

	ast = Util.dupTree(n3);
	ast5.addChild(ast);
	ast.setParent(ast5);

        MethodCallNode mc2 = new MethodCallNode(ast2);
        mc2.setVarDef(true);
        skipMCTable.put(mc2, ast5);

        _addNodeEndLoop(mc2, node, ast2, ast5, skipMCTable);
    }

    ///////////////////////////////////////////////////////////////////
    ////                      private variables                    ////
}
